#ifndef LINE_HPP
#define LINE_HPP

#include "basic_primitives.hpp"
#include <vl/vec.hpp>


#define SIGN(x_) ((x_) < 0 ? -1 : (x_) > 0 ? 1 : 0)

// Line primitive with a relatively fast and pixel accurate clipping routine.

template< typename BitmapT, typename BlitterT >
void line( BitmapT* bitmap, vl::ivec p1, vl::ivec p2, typename BlitterT::SrcColorT color, BlitterT& blitter )
{
	long xdiff = p2.x - p1.x;
 	long ydiff = p2.y - p1.y;
 
	long sx = SIGN(xdiff);
 	long sy = SIGN(ydiff);
 
 	xdiff = labs(xdiff);
 	ydiff = labs(ydiff);
 	
	#define WORK(a, b) { \
 		long i = a##diff >> 1; \
 		long c = a##diff; \
		if ( s##a > 0 ) \
		{ \
			if ( p1.a < bitmap->clip.a##1 ) \
			{ \
				long clipDiff = bitmap->clip.a##1 - p1.a; \
				p1.a = bitmap->clip.a##1; \
				c -= clipDiff; \
				clipDiff = (clipDiff * b##diff) + (a##diff+1 >> 1); \
				p1.b += ( ( clipDiff-1 ) / a##diff ) * s##b; \
				i = ( clipDiff ) % (a##diff); \
				if ( i!= 0 ) i = a##diff - i; \
			} \
			if ( p2.a >= bitmap->clip.a##2 ) \
			{ \
				c -= p2.a - bitmap->clip.a##2 + 1; \
			} \
		}else \
		{ \
			if ( p1.a >= bitmap->clip.a##2 ) \
			{ \
				long clipDiff = p1.a - (bitmap->clip.a##2 - 1); \
				p1.a = (bitmap->clip.a##2 - 1); \
				c -= clipDiff; \
				clipDiff = (clipDiff * b##diff) + (a##diff+1 >> 1); \
				p1.b += ( ( clipDiff-1 ) / a##diff ) * s##b; \
				i = ( clipDiff ) % (a##diff); \
				if ( i!= 0 ) i = a##diff - i; \
			} \
			if ( p2.a < bitmap->clip.a##1 ) \
			{ \
				c -= bitmap->clip.a##1 - p2.a; \
			} \
		} \
 		while(c-- >= 0) { \
			if ( p1.b < bitmap->clip.b##2 && p1.b >= bitmap->clip.b##1 ) { \
				unsigned char* data = bitmap->data; \
				data += bitmap->pitch * p1.y + p1.x * BitmapT::SizeOfPixel; \
				blitter.blitColorToPixel( *reinterpret_cast< typename BitmapT::ColorType* >(data), color ); } \
 			i -= b##diff; \
 			p1.a += s##a; \
 			if(i < 0) p1.b += s##b, i += a##diff; } }
 			
	if(xdiff > ydiff)
 		WORK(x, y)
 	else
 		WORK(y, x)

 	#undef WORK
}

#undef SIGN

#endif // LINE_HPP
